package io.renren.modules.commodity.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mysql.cj.jdbc.MysqlDataSource;
import io.renren.common.utils.PageUtils;
import io.renren.common.utils.Query;
import io.renren.modules.behavior.entity.UserBehaviorLogEntity;
import io.renren.modules.behavior.service.UserBehaviorLogService;
import io.renren.modules.commodity.dao.CommodityDao;
import io.renren.modules.commodity.entity.CommodityEntity;
import io.renren.modules.commodity.service.CommodityImgService;
import io.renren.modules.commodity.service.CommodityService;
import io.renren.modules.sys.entity.SysUserEntity;
import io.renren.modules.sys.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.impl.common.LongPrimitiveIterator;
import org.apache.mahout.cf.taste.impl.model.jdbc.MySQLJDBCDataModel;
import org.apache.mahout.cf.taste.impl.neighborhood.NearestNUserNeighborhood;
import org.apache.mahout.cf.taste.impl.recommender.GenericUserBasedRecommender;
import org.apache.mahout.cf.taste.impl.similarity.EuclideanDistanceSimilarity;
import org.apache.mahout.cf.taste.model.DataModel;
import org.apache.mahout.cf.taste.neighborhood.UserNeighborhood;
import org.apache.mahout.cf.taste.recommender.RecommendedItem;
import org.apache.mahout.cf.taste.recommender.Recommender;
import org.apache.mahout.cf.taste.similarity.UserSimilarity;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;


@Service("commodityService")
@Slf4j
public class CommodityServiceImpl extends ServiceImpl<CommodityDao, CommodityEntity> implements CommodityService {

    @Autowired
    private CommodityImgService commodityImgService;

    @Autowired
    private UserBehaviorLogService userBehaviorLogService;

    @Autowired
    private SysUserService sysUserService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {

        QueryWrapper<CommodityEntity> queryWrapper = new QueryWrapper<>();
        if (Query.STATUS_ACTIVED.equals(params.get(Query.STATUS))) {
            queryWrapper.eq("status", 1);
        }

        // 增加商品类型筛选
        if (params.containsKey("commodityType")) {
            queryWrapper.eq("commodity_type", params.get("commodityType"));
        }


        IPage<CommodityEntity> page = this.page(
                new Query<CommodityEntity>().getPage(params),
                queryWrapper
        );

        List<CommodityEntity> records = page.getRecords();

        for (CommodityEntity record : records) {
            record.setImgUrl(commodityImgService.queryImgUrlsByCommodityId(record.getId()));
        }

        page.setRecords(records);

        return new PageUtils(page);
    }

    @Override
    public CommodityEntity queryById(Long id) {

        CommodityEntity commodityEntity = baseMapper.selectById(id);

        // 如果没有找到直接记录日志返回一个空
        if (commodityEntity == null) {
            log.warn("找不到id为{}的商品", id);
            return null;
        }

        // 通过用户行为日志表判断用户是否对该商品点赞过或收藏过
        SysUserEntity user = (SysUserEntity) SecurityUtils.getSubject().getPrincipal();
        Long userId = user.getUserId();

        UserBehaviorLogEntity like = userBehaviorLogService.queryIsLike(userId, id);
        commodityEntity.setLike(like != null);

        UserBehaviorLogEntity collection = userBehaviorLogService.queryIsCollection(userId, id);
        commodityEntity.setCollect(collection != null);

        return commodityEntity;
    }

    @Override
    public void userLikeOrDislike(Long itemId) {

        // 通过用户行为日志表判断用户是否对该商品点赞过
        SysUserEntity user = (SysUserEntity) SecurityUtils.getSubject().getPrincipal();
        Long userId = user.getUserId();

        UserBehaviorLogEntity likeEntity = userBehaviorLogService.queryIsLike(userId, itemId);

        // 如果记录为空，则新建一条用户点赞的记录
        if (likeEntity == null) {
            // 用户点赞，记录在用户行为日志表
            UserBehaviorLogEntity entity = new UserBehaviorLogEntity();
            entity.setUserId(userId);
            entity.setItemId(itemId);
            entity.setUserBehaviorType(1);
            userBehaviorLogService.save(entity);

            // 增加商品表中的点赞数量
            addCommodityLikeCount(itemId);

        } else {
            // 用户取消点赞，记录再用户行为日志表
            likeEntity.setStatus(0);
            userBehaviorLogService.saveOrUpdate(likeEntity);

            // 减少商品表中的点赞数量
            reduceCommodityLikeCount(itemId);
        }

    }

    @Override
    public void userCollectionOrNot(Long itemId) {

        // 通过用户行为日志表判断用户是否对该商品点赞过
        SysUserEntity user = (SysUserEntity) SecurityUtils.getSubject().getPrincipal();
        Long userId = user.getUserId();

        UserBehaviorLogEntity collectionEntity = userBehaviorLogService.queryIsCollection(userId, itemId);

        // 如果记录为空，则新建一条用户点赞的记录
        if (collectionEntity == null) {
            UserBehaviorLogEntity entity = new UserBehaviorLogEntity();
            entity.setUserId(userId);
            entity.setItemId(itemId);
            entity.setUserBehaviorType(2);
            userBehaviorLogService.save(entity);

            // 增加商品表中的收藏数量
            addCommodityCollectionCount(itemId);
        } else {
            collectionEntity.setStatus(0);
            userBehaviorLogService.saveOrUpdate(collectionEntity);

            // 减少商品表中的收藏数量
            reduceCommodityCollectionCount(itemId);
        }
    }

    @Override
    public void userCommentItem(UserBehaviorLogEntity userBehaviorLogEntity) {

        // 通过用户行为日志表判断用户是否对该商品点赞过
        SysUserEntity user = (SysUserEntity) SecurityUtils.getSubject().getPrincipal();
        Long userId = user.getUserId();

        UserBehaviorLogEntity entity = new UserBehaviorLogEntity();
        entity.setUserId(userId);
        entity.setItemId(userBehaviorLogEntity.getItemId());

        if (userBehaviorLogEntity.getCommentStar() != null) {
            entity.setCommentStar(userBehaviorLogEntity.getCommentStar());
            entity.setCommentContent(userBehaviorLogEntity.getCommentContent());
            entity.setUserBehaviorType(3);
        } else {
            entity.setCommentReply(userBehaviorLogEntity.getCommentContent());
            entity.setUserBehaviorType(5);
        }

        userBehaviorLogService.save(entity);

    }

    @Override
    public List<UserBehaviorLogEntity> allItemComment(Long itemId) {

        QueryWrapper<UserBehaviorLogEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("item_id", itemId)
                .eq("user_behavior_type", 3)
                .or()
                .eq("user_behavior_type", 5);
        List<UserBehaviorLogEntity> lists = userBehaviorLogService.list(wrapper);
        for (UserBehaviorLogEntity entity : lists) {
            Long userId = entity.getUserId();
            SysUserEntity userEntity = sysUserService.getById(userId);
            String userName = userEntity.getUsername();
            entity.setUserName(userName);
        }

        return lists;
    }

    @Override
    public List<CommodityEntity> guessUserLike() {

        // 用户协同
        List<RecommendedItem> userRecommendedItem = userSimilarity();
        List<CommodityEntity> result = new ArrayList<>();
        if (userRecommendedItem == null || userRecommendedItem.size() == 0) {
            return null;
        }

        for (RecommendedItem item : userRecommendedItem) {
            long itemId = item.getItemID();
            CommodityEntity commodityEntity = baseMapper.selectById(itemId);
            result.add(commodityEntity);
        }

        return result;
    }

    /**
     * 增加商品点赞数量
     *
     * @param itemId 商品id
     */
    public void addCommodityLikeCount(Long itemId) {

        QueryWrapper<CommodityEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", itemId);
        CommodityEntity commodityEntity = baseMapper.selectOne(queryWrapper);

        commodityEntity.setLikeCount(commodityEntity.getLikeCount() + 1);
        saveOrUpdate(commodityEntity);
    }

    /**
     * 减少商品点赞数量
     *
     * @param itemId 商品id
     */
    public void reduceCommodityLikeCount(Long itemId) {

        QueryWrapper<CommodityEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", itemId);
        CommodityEntity commodityEntity = baseMapper.selectOne(queryWrapper);

        commodityEntity.setLikeCount(commodityEntity.getLikeCount() - 1);
        saveOrUpdate(commodityEntity);
    }

    /**
     * 增加商品收藏数量
     *
     * @param itemId 商品id
     */
    public void addCommodityCollectionCount(Long itemId) {

        QueryWrapper<CommodityEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", itemId);
        CommodityEntity commodityEntity = baseMapper.selectOne(queryWrapper);

        commodityEntity.setCollectCount(commodityEntity.getCollectCount() + 1);
        saveOrUpdate(commodityEntity);
    }

    /**
     * 增加商品收藏数量
     *
     * @param itemId 商品id
     */
    public void reduceCommodityCollectionCount(Long itemId) {

        QueryWrapper<CommodityEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", itemId);
        CommodityEntity commodityEntity = baseMapper.selectOne(queryWrapper);

        commodityEntity.setCollectCount(commodityEntity.getCollectCount() - 1);
        saveOrUpdate(commodityEntity);
    }

    /**
     * 用户的协同推荐
     * @return  推荐的商品id
     */
    public List<RecommendedItem> userSimilarity() {

        MysqlDataSource dataSource = new MysqlDataSource();
        dataSource.setServerName("localhost");
        try {
            dataSource.setServerTimezone("UTC");
        } catch (SQLException e) {
            e.printStackTrace();
        }
        dataSource.setUser("root");
        dataSource.setPassword("123456");
        dataSource.setDatabaseName("mybatis");

        DataModel dataModel = new MySQLJDBCDataModel(dataSource, "mahout_test", "user_id", "item_id", "item_account", "create_time");

        /*
         * 用户相似度定义
         *
         * 例如：点赞 0.5分， 收藏 1.5分，评论 2分，浏览时间 1分。
         *
         * 如果一个用户点赞加收藏加评论（评论给了4颗星），浏览时间是15分钟
         * 那他对这件商品的得分就是  0.5 + 1.5 + 2*（4/5） + 1 = 4.6
         *
         * 如果一个用户点赞加评论（评论给了3颗星），浏览时间是3分钟
         * 那他对这件商品的得分就是 0.5 + 2*（3/5） + 0.5 = 2.2
         */
        List<RecommendedItem> recommend = null;

        try {
            //余弦相似度
//        UserSimilarity userSimilarity = new UncenteredCosineSimilarity(dataModel);
            //欧几里得相似度
            UserSimilarity userSimilarity = new EuclideanDistanceSimilarity(dataModel);
            //皮尔森相似度
//        UserSimilarity userSimilarity = new PearsonCorrelationSimilarity(dataModel);

            //定义用户的2-最近邻
            UserNeighborhood userNeighborhood = new NearestNUserNeighborhood(2, userSimilarity, dataModel);
            //定义推荐引擎
            Recommender recommender = new GenericUserBasedRecommender(dataModel, userNeighborhood, userSimilarity);

            // 获取当前用户id
            SysUserEntity user = (SysUserEntity) SecurityUtils.getSubject().getPrincipal();
            Long userId = user.getUserId();


            recommend = recommender.recommend(userId, 10);
        } catch (Exception e) {
            log.warn("用户协同出错了");
        }

        return recommend;
    }

}